package winOrDie.Net.Proxy;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

import winOrDie.Net.WoD_Net_Protocol_ASCII;
import winOrDie.Net.Server.WoD_Server_Client;
import winOrDie.Net.Server.WoD_Server_ControlChannel;
import winOrDie.Net.Server.WoD_Server_ControlChannel_Event;

public class Wod_Proxy_Server 
{
	
	private Control_Servidor controlServidor = null;
	
	/**
	 * Clase cliente
	 */
	public class Wod_Proxy_Server_Client 
	{
		private int ID = -1;
		private Socket socket = null;
		private Control_Cliente controlCliente = null;
		
		
		public void setID(int iD) {
			ID = iD;
		}

		public int getID() {
			return ID;
		}

		public Socket getSocket() {
			return socket;
		}

		
		
		public Control_Cliente getControlCliente() {
			return controlCliente;
		}

	
		public Wod_Proxy_Server_Client(int ID, Socket socket) 
		{
			this.ID = ID;
			this.socket = socket;
			controlCliente = new Control_Cliente(this);
			Thread thread = new Thread(controlCliente);
			thread.start();
		}
	}
	

	/**
	 * Clase que escucha clientes. Añade al vector de clientes la nueva conexión.
	 * 
	 */
	private class Escucha_Nuevos_Clientes implements Runnable
	{
		
		public Escucha_Nuevos_Clientes() {

		}
		
		
		@Override
		public void run() {
			Socket socket;
			try {
				socket = serverSocket.accept();
				Wod_Proxy_Server_Client client = new Wod_Proxy_Server_Client(-1, socket);
				clients.addElement(client);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
	
	/**
	 * Clase de control cliente.
	 * Los mensajes recibidos por los clientes son standards.
	 *
	 */
	private class Control_Cliente implements Runnable
	{
		private InputStream inputStream = null;
		private DataInputStream dataInputStream = null;
		private OutputStream outputStream = null;
		private DataOutputStream dataOutputStream = null;
		
		private Wod_Proxy_Server_Client client = null;
		
		public Control_Cliente(Wod_Proxy_Server_Client client) {
			try {
				this.client = client;
				inputStream = this.client.getSocket().getInputStream();
				dataInputStream = new DataInputStream(inputStream);
				
				outputStream = this.client.getSocket().getOutputStream();
				dataOutputStream = new DataOutputStream(outputStream);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		public void send_Message (String message) throws Exception
		{
			dataOutputStream.writeUTF(message);
		}
		String message = null;
		@Override
		public void run() {
			// TODO Auto-generated method stub
			try {
				message = dataInputStream.readUTF();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			String message_parts[] = message.split(" ");
			
			String message_toSend = new String();
			
			String IP = client.getSocket().getInetAddress().getHostAddress();
			int port = client.getSocket().getPort();
			
			message_toSend = WoD_Net_Protocol_ASCII.Proxy.Proxy + " ";
			message_toSend += IP + " ";
			message_toSend += port + " ";
			message_toSend += message;
			
			
			try {
				controlServidor.send_Message(message);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	
	
	/**
	 * Clase de control servidor. 
	 * Los mensajes recibidos por el servidor contienen la cabecera PR + IP + PUERTO
	 *
	 */
	private class Control_Servidor implements Runnable
	{
		
		
		private InputStream inputStream = null;
		private DataInputStream dataInputStream = null;
		private OutputStream outputStream = null;
		private DataOutputStream dataOutputStream = null;
		
		public Control_Servidor() {
			try {
				inputStream = Socket_Server.getInputStream();
				dataInputStream = new DataInputStream(inputStream);
				
				outputStream = Socket_Server.getOutputStream();
				dataOutputStream = new DataOutputStream(outputStream);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		
		public void send_Message (String message) throws Exception
		{
			dataOutputStream.writeUTF(message);
		}
		
		@Override
		public void run() {
			
			
			String message = null;
			try {
				message = dataInputStream.readUTF();
				
				String message_parts[] = message.split(" ");
				
				String message_toSend = null;
				
				
				String IP = message_parts[1];
				int port = Integer.valueOf(message_parts[2]);
				int ID = Integer.valueOf(message_parts[4]);
				
				if (message_parts[3].equals(WoD_Net_Protocol_ASCII.GameMenu.Join_Game_OK))
				{
					
					for (Wod_Proxy_Server_Client client : clients) {
						if ((client.getSocket().getInetAddress().getHostAddress().equals(IP)) &&
								(client.getSocket().getPort() == port))
						{
							client.setID(ID);
							try {
								client.getControlCliente().send_Message(get_MessageFromProxyMessage(message));
							} catch (Exception e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}							
						}
					}
				}
				else if (message_parts[3].equals(WoD_Net_Protocol_ASCII.GameMenu.Join_Game_KO))
				{
					for (Wod_Proxy_Server_Client client : clients) {
						if ((client.getSocket().getInetAddress().getHostAddress().equals(IP)) &&
								(client.getSocket().getPort() == port))
						{
							try {
								client.getControlCliente().send_Message(get_MessageFromProxyMessage(message));
							} catch (Exception e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}							
						}
					}
				}
					
				else
				{
					for (Wod_Proxy_Server_Client client : clients) {
						if (client.getID() != -1)
						{
							dataOutputStream.writeUTF(get_MessageFromProxyMessage(message));
						}
					}
				}
					
				
				
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
			
		}
	}
	
	
	
	
	
	
	/**
	 * Vector de clientes
	 */
	private Vector<Wod_Proxy_Server_Client> clients = null;
	private Socket Socket_Server = null;
	
	
	/**
	 * Puerto de escucha del proxy
	 * Servidor de sockets
	 */
	private int listen_port = -1;
	private ServerSocket serverSocket = null;
	
	
	
	/**
	 * Instanciamos Servidor Proxy.
	 * @param listen_port
	 */
	public Wod_Proxy_Server(int listen_port) {
		this.listen_port = listen_port;
		
		try {
			serverSocket = new ServerSocket(listen_port);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return;
		}
		
		
		/**
		 * El primero es el servidor
		 */
		try {
			Socket_Server = serverSocket.accept();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		
	}
	
	
	//FUNCIONES ESTÁTICAS PARA EL TRATAMIENTO DE LOS STRINGS
	
	/**
	 * Envía información con cabecera de Proxy: PR + IP + PUERTO
	 * @param woDServerControlChannel
	 * @param message
	 * @throws Exception
	 */
	public static void sendData_With_Proxy(
			WoD_Server_ControlChannel woDServerControlChannel,
			String message) throws Exception
	{
		woDServerControlChannel.sendData(proxy_Message_to_Send(
				woDServerControlChannel.getWoDServerClient(), message)
				);
	}
	
	/**
	 * Añadimos cabecera PR + IP + PUERTO al mensaje original
	 * @param woDServerClient
	 * @param message
	 * @return
	 */
	public static String proxy_Message_to_Send(
			WoD_Server_Client woDServerClient,
			String message)
	{
		String message_toSend = new String();
		message_toSend += WoD_Net_Protocol_ASCII.Proxy.Proxy + " ";
		message_toSend += woDServerClient.getHostDirection() + " ";
		message_toSend += woDServerClient.getTcp_port() + " ";
		message_toSend += message;
		
		return message_toSend;
	}
	
	/**
	 * Obtenemos mensaje original enviado por el Servidor
	 * @param message
	 * @return
	 */
	public static String get_MessageFromProxyMessage(String message)
	{
		String message_parts[] = message.split(" ");
		String message_toSend = new String();
		for (int i = 3; i < message_parts.length -1 ; i++) {
			message_toSend += message_parts[i] + " ";
		}
		message_toSend += message_parts[message_parts.length - 1];
		return message_toSend;
	}

}
